////////////////////////////////////////////////////////////////////////////////////
//
// Main rendering class. Provides base functionality to render the XML produced
// by the web controls.
//
//
// Created by: Vincent Rothwell
//
////////////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using Mvp.Xml.Common.Xsl;
using System.Xml;
using Microsoft.SharePoint;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.IO;
using System.Web;
using ARF.Web.Utility;
using System.Configuration;

namespace ARF.Web.Controls
{
    public class XslRenderControl : Control
    {
        protected XslRenderControl() { }

        private string _xslName;
        private string _xslPath = "/Style Library/XSL Style Sheets/Controls/";
        private IXPathNavigable _xmlObject;
        private ArfCache _cacheObject;
        private static string _xslRenderControlDef;

        private Control _owner;

        protected bool _allowXslSelection = false;

        public bool AllowXslSelection
        {
            get { return _allowXslSelection; }
            set { _allowXslSelection = value; }
        }

        public ArfCache Cache
        {
            get { if (_cacheObject == null) _cacheObject = new ArfCache(CacheKey);  return _cacheObject; }
            set { _cacheObject = value; }
        }

        protected virtual string CacheKey
        {
            get { return UniqueID; }
        }

        public IXPathNavigable XmlObject
        {
            get { return _xmlObject; }
            set { _xmlObject = value; }
        }

        public virtual string XslPath
        {
            get { return _xslPath; }
            set { _xslPath = value; }
        }

        public virtual string XslName
        {
            get { return _xslName; }
            set { _xslName = value; }
        }

        public bool IsCached
        {
            get { return false; }
        }

        public string XslFullPath
        {
            get
            {
                if (SPContext.Current.Site.ServerRelativeUrl != "/")
                    return SPContext.Current.Site.ServerRelativeUrl + XslPath + XslName;

                return XslPath + XslName;
            }
        }

        // Placeholder method for to allow furture extensions to the creation of
        // XSL renderers
        public static XslRenderControl Create()
        {
            return new XslRenderControl();
        }
 
        public static XslRenderControl Create(Control owner)
        {
            try
            {
                if (string.IsNullOrEmpty(_xslRenderControlDef))
                {
                    _xslRenderControlDef = ConfigurationManager.AppSettings["ARF-XslRenderControl"];
                }
                if (!string.IsNullOrEmpty(_xslRenderControlDef))
                {
                    string[] arDef = _xslRenderControlDef.Split(new char[] { ',' }, 2);
                    XslRenderControl oRender = (XslRenderControl)Activator.CreateInstance(arDef[1], arDef[0]).Unwrap();
                    oRender.Owner = owner;
                    return oRender;
                }
            }
            catch (Exception ex)
            {
                Log.Trace(ex);
            }
        
            XslRenderControl oNew = new XslRenderControl();
            oNew.Owner = owner;
            return oNew;
        }

        public Control Owner
        {
            get
            {
                return this._owner;
            }
            set
            {
                this._owner = value;
            }
        }

        protected virtual string XmlXsl
        {
            get
            {
                return "<xsl:stylesheet xmlns:x=\"http://www.w3.org/2001/XMLSchema\" version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" exclude-result-prefixes=\"xsl x\"><xsl:output omit-xml-declaration=\"yes\" method=\"xml\" indent=\"yes\"/><xsl:template match=\"/\"><textarea style=\"width:100%;height:150px\"><xsl:copy-of select=\".\"/></textarea></xsl:template></xsl:stylesheet>";
            }
        }

        protected override void Render(HtmlTextWriter writer)
        {
            try
            {
                if (XmlObject == null)
                {
                    Log.Trace("No XML document to transform");
                    //writer.Write("<span style='color:red'>No XML provided</span>");
                    return;
                }

                if (HttpContext.Current.Request["arf-xml"] != null)
                {
                    XmlDocument oXmlXslDoc = new XmlDocument();
                    oXmlXslDoc.LoadXml(XmlXsl);
                    MvpXslTransform oXmlTrans = new MvpXslTransform(); oXmlTrans.Load(oXmlXslDoc);
                    TransformXML(writer, oXmlTrans);
                }

                MvpXslTransform oTransform = LoadTransform();

                if (AllowXslSelection && SPContext.Current.FormContext.FormMode == Microsoft.SharePoint.WebControls.SPControlMode.Edit)
                {
                    writer.Write("<div>Xsl Template: <select name='XSL_" + ID + "'>");
                    SPFolder oFolder = SPContext.Current.Site.RootWeb.GetFolder(XslPath);

                    foreach (SPFile oFile in oFolder.Files)
                        writer.Write(string.Format("<option value='{2}' {1}>{0}</option>", ((string.IsNullOrEmpty(oFile.Title)) ? oFile.Name : oFile.Title), ((XslName == oFile.Name) ? " selected='true' " : ""), oFile.Name));
                }

                if (oTransform != null) TransformXML(writer, oTransform);

                if (AllowXslSelection && SPContext.Current.FormContext.FormMode == Microsoft.SharePoint.WebControls.SPControlMode.Edit)
                    writer.Write("</select></div>");
            }
            catch (Exception ex)
            {
                Log.Trace(ex);
            }
        }

        protected virtual void TransformXML(HtmlTextWriter writer, MvpXslTransform oTransform)
        {
            if (Cache.IsCached) { writer.Write(Cache.Value); return; }

            StringWriter sw = new StringWriter();
            HtmlTextWriter htw = new HtmlTextWriter(sw);

            XmlInput oInput = new XmlInput(XmlObject);
            XmlOutput oOutput = new XmlOutput(htw);

            oTransform.Transform(oInput, BuildArgumentList(), oOutput);

            string sHTML = sw.ToString();

            writer.Write(sHTML);

            htw.Dispose();
            sw.Dispose();

            if (Cache.Enabled) Cache.Value = sHTML;
        }

        protected string XslTransformCacheKey
        {
            get
            {
                return "XSL: " + SPContext.Current.Site.Url + XslFullPath;
            }
        }

        private MvpXslTransform LoadTransform()
        {
            if (string.IsNullOrEmpty(XslName)) return null;

            object oCachedTransform = HttpContext.Current.Cache[XslTransformCacheKey];

            if (oCachedTransform != null && !SPContext.Current.Web.UserIsWebAdmin) return (MvpXslTransform)oCachedTransform;

            MvpXslTransform oTransform = new MvpXslTransform(ARFSettings.DebugEnabled);

            string sXSL = SPContext.Current.Site.RootWeb.GetFileAsString(XslFullPath);

            SharePointXmlUrlResolver oResolver = new SharePointXmlUrlResolver(SPContext.Current.Site.Url, XslPath);

            oTransform.Load(new XmlTextReader(new StringReader(sXSL)), XsltSettings.Default, oResolver);

            if (!SPContext.Current.Web.UserIsWebAdmin) HttpContext.Current.Cache.Add(XslTransformCacheKey, oTransform, null, DateTime.Now.AddMinutes(10), System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.AboveNormal, null);

            return oTransform;
        }

        protected XsltArgumentList BuildArgumentList()
        {
            XsltArgumentList oArguments = new XsltArgumentList();



            return oArguments;
        }
    }
}
